﻿using System;

namespace SRS.Encryption
{
    /// <summary>
    /// Cipher Block Caining Encryption
    /// </summary>
    public class CBC : SRSEncryption
    {
        public CBC()
            : base()
        {
        }


        /// <summary>
        /// Encrypt
        /// </summary>
        /// <param name="key">Encryption key</param>
        /// <param name="plainText">Plain text which are encrypted</param>
        /// <returns></returns>
        public override byte[] Encrypt(byte[] key, byte[] plainText)
        {
            int i;
            int length = plainText.Length;
            int keyLength = key.Length;
            byte[] cipherText = new byte[GenerateNewLength(length, keyLength)];
            byte[] cipherTextBlock = GenerateInitialVector(key);

            for (i = 0; i < length; i += keyLength)
            {
                cipherTextBlock = EncryptBlock(key, XORBlock(GetBlock(plainText, i, keyLength), cipherTextBlock));
                Array.Copy(cipherTextBlock, 0, cipherText, i, keyLength);
            }

            return cipherText;
        }


        public override byte[] Encrypt(byte[] key, byte[] plainText, int unitLength)
        {
            return Encrypt(key, plainText);
        }


        /// <summary>
        /// Decrypt
        /// </summary>
        /// <param name="key">Decryption key</param>
        /// <param name="cipherText">Cipher text which are decrypted</param>
        /// <returns></returns>
        public override byte[] Decrypt(byte[] key, byte[] cipherText)
        {
            int i;
            int length = cipherText.Length;
            int keyLength = key.Length;
            byte[] plainText = new byte[GenerateNewLength(length, keyLength)];
            byte[] cipherTextBlock = GenerateInitialVector(key);
            byte[] preCipherTextBlock = GenerateInitialVector(key);
            byte[] plainTextBlock;

            for (i = 0; i < length; i += keyLength)
            {
                cipherTextBlock = GetBlock(cipherText, i, keyLength);
                plainTextBlock = XORBlock(DecryptBlock(key, cipherTextBlock), preCipherTextBlock);
                Array.Copy(plainTextBlock, 0, plainText, i, keyLength);
                preCipherTextBlock = cipherTextBlock;
            }

            return plainText;
        }

        public override byte[] Decrypt(byte[] key, byte[] cipherText, int unitLength)
        {
            return Decrypt(key, cipherText);
        }
    }
}
